/*******************************************************\
|* Author: Trevor Sundberg
\*******************************************************/

// Includes
#include "SkugoTypes.hpp"
#include <cstring>
#include <string>
#include <set>

// Get rid of a symbols warning :/
int ExportSymbols = 0;

namespace Skugo
{
  // Using directives
  using std::string;
  using std::set;

  // A default 'get/set' policy for standard strings
  template <>
  struct StringPolicy<string>
  {
    const char* Get(const string& str)
    {
      return str.c_str();
    }

    void Set(string& str, const char* newValue)
    {
      str = newValue;
    };
  };

  // A default 'get/set' policy for C strings
  template <>
  struct StringPolicy<const char*>
  {
    typedef set<const char*> StrSet;
    typedef StrSet::iterator StrIter;

    ~StringPolicy()
    {
      // Loop through the remaining allocated strings
      for (StrIter it = mAllocatedStrings.begin(); it != mAllocatedStrings.end(); ++it)
      {
        // Delete each allocated strings
        delete[] *it;
      }

      // Clear out the allocated strings (just for safety I guess)
      mAllocatedStrings.clear();
    }

    const char* Get(const char* str)
    {
      return str;
    }

    void Set(const char*& str, const char* newValue)
    {
      // If the strings are different...
      if (std::strcmp(str, newValue) != 0)
      {
        // Get the length of the new string
        sizeType length = std::strlen(newValue);

        // Allocate a buffer big enough to hold the new string
        char* buffer = new char[length];

        // Copy the string into an allocated buffer
        std::memcpy(buffer, newValue, length);

        // Put the allocated string into the set
        mAllocatedStrings.insert(buffer);

        // Attempt to find the old string in the set of allocated strings
        StrIter found = mAllocatedStrings.find(str);

        // If we found it...
        if (found != mAllocatedStrings.end())
        {
          // Remove it from the set
          mAllocatedStrings.erase(found);

          // De-allocate the old one
          delete[] str;
          str = NULL;
        }

        // Finally, re-point the string at our newly allocated one
        str = buffer;
      }
    };

    // A set of all the allocated strings
    StrSet mAllocatedStrings;
  };
}
